import importlib.util
import os
import types
from datetime import datetime as datetime_
from datetime import timedelta
import pandas as pd

from core.map_const import IntervalMap
from core.constant import *
from conf import conf


# 返回日志标准前缀
def datetime_str(full=False, data_name=False):
    if data_name:
        return datetime_.now().strftime("%m_%d-%H_%M")
    if full:
        return datetime_.now().strftime("[%m-%d %H:%M:%S]: ")
    else:
        return datetime_.now().strftime("[%H:%M:%S]: ")


def get_date_str(move: int = 0):
    if move == 0:
        return datetime_.now().strftime("%Y-%m-%d")
    else:
        return (datetime_.now() - timedelta(days=move)).strftime("%Y-%m-%d")


def gen_result_folder_name(result_folder: ResultFolder):
    # 生成当前时间对应的回测模块结果文件夹的名称
    return conf.FileManager.f.value.join([result_folder.name, datetime_str(data_name=True)])


def get_latest_file(dir_path, file_suffix):
    # 获取指定目录下所有的md文件
    md_files = [os.path.join(dir_path, f) for f in os.listdir(dir_path) if f.endswith(file_suffix)]

    # 按修改时间排序md文件
    latest_md_file = max(md_files, key=os.path.getmtime, default=None)

    return latest_md_file


def load_module_from_path(file_path):
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"The file {file_path} does not exist.")

    module_name = os.path.splitext(os.path.basename(file_path))[0]
    spec = importlib.util.spec_from_file_location(module_name, file_path)
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


def get_method_from_class(ori_class):
    # 获取类中非父类方法名
    methods = []
    # 获取类的所有属性和方法
    for name, func in ori_class.__dict__.items():
        # 过滤出方法，并排除继承自父类的方法
        if isinstance(func, types.FunctionType) and name != "__init__":
            methods.append(name)
    return methods


def get_min_interval(interval_ls: list[Interval]):

    min_interval = None
    for interval_o in interval_ls:
        if min_interval is None:
            min_interval = interval_o
        else:
            min_interval = interval_o if IntervalMap[interval_o] < IntervalMap[min_interval] else min_interval

    return min_interval


def get_name_from_value(value, enum_c):
    for o in enum_c:
        if o.value == value:
            return o


def add_sr_to_df(series, dataframe=None):
    if dataframe is None:
        dataframe = pd.DataFrame(columns=series.index)  # 创建一个新的 DataFrame，列名与 Series 索引相同
    series_df = series.to_frame().T
    dataframe = pd.concat([dataframe, series_df], axis=0)
    # dataframe = dataframe.append(series)  # 添加 Series 到 DataFrame
    return dataframe


def get_ui_value(values, indices, widget_category: WidgetCategory):
    if widget_category == WidgetCategory.Entry:
        if len(values) == len(indices) == 1 and indices[0] == 0:
            return values[indices[0]]
        else:
            raise ValueError(f"{widget_category.value}组件获取值失败。")
    elif widget_category == WidgetCategory.Combobox:
        if values and indices:
            return values[indices[0]]
        else:
            return []
    elif widget_category == WidgetCategory.Filedialog:
        raise ValueError(f"{widget_category.value}组件获取值失败。")
    elif widget_category == WidgetCategory.CheckButton:
        if values and indices:
            value_ls = []
            for i, value in enumerate(values):
                if i in indices:
                    value_ls.append(value)
            return value_ls
        else:
            return []
    elif widget_category == WidgetCategory.ScrolledText:
        if len(values) == len(indices) == 1 and indices[0] == 0:
            return values[indices[0]]
        else:
            raise ValueError(f"{widget_category.value}组件获取值失败。")
    else:
        raise ValueError("未设置获取值方法的组件类型")


def gen_save_table_fig(table_data, fig_path):
    from textwrap import wrap

    # 文本换行函数
    def wrap_text(text, width=10):
        return '\n'.join(wrap(str(text), width))

    import matplotlib.pyplot as plt
    fig, ax = plt.subplots(figsize=(10, 10))
    # 创建表格数据
    df = pd.DataFrame(table_data)
    # 应用文本换行
    for column in df.columns:
        df[column] = df[column].apply(lambda x: wrap_text(x, 10))

    # 绘制表格
    ax.axis("tight")
    ax.axis("off")

    # 创建表格并设置样式
    table = ax.table(cellText=df.values, colLabels=df.columns, cellLoc="center", loc="center",
                      bbox=[0.2, 0, 0.6, 1])
    table.auto_set_font_size(False)
    table.set_fontsize(12)
    table.scale(1.2, 1.2)

    # 设置表格样式：单双行不同背景色
    for i, key in enumerate(table.get_celld().keys()):
        cell = table.get_celld()[key]
        cell.set_edgecolor("black")
        if key[0] == 0:
            cell.set_text_props(weight="bold", color="white")
            cell.set_facecolor("gray")
        elif key[0] % 2 == 1:
            cell.set_facecolor("#f0f0f0")
        else:
            cell.set_facecolor("white")

    plt.tight_layout()
    plt.savefig(fig_path)
    print(f"{fig_path}已生成。")


def value2px(value, max_min_val_ls, width):
    if max_min_val_ls[0] - max_min_val_ls[1] != 0:
        rate = width / (max_min_val_ls[0] - max_min_val_ls[1])
    else:
        rate = 0
    px = (max_min_val_ls[0] - value) * rate
    return px


def px2value(px, max_min_val_ls, width):
    if '.' in str(max_min_val_ls[0]):
        max_val_decimal_num = len(str(max_min_val_ls[0]).split('.')[1])
    else:
        max_val_decimal_num = 0
    if '.' in str(max_min_val_ls[1]):
        min_val_decimal_num = len(str(max_min_val_ls[1]).split('.')[1])
    else:
        min_val_decimal_num = 0

    decimal_num = max([max_val_decimal_num, min_val_decimal_num])
    if decimal_num > 3:
        decimal_num = 3
    rate = (max_min_val_ls[0] - max_min_val_ls[1]) / width
    value = round(max_min_val_ls[0] - (px - 0) * rate, decimal_num)
    return value

